/*
 * File:   TestMain.cpp
 * Author: root
 *
 * Created on November 13, 2008, 5:22 PM
 */
#include "Strategy.h"
#include "GameState.h"
#include "Query.h"
#include "Player.h"
#include "GameManager.h"
#include "Agent31.h"
#include "strategies/RandomDiscardStrategy.h"
#include "strategies/RandomDrawingStrategy.h"
#include "strategies/RandomKnockingStrategy.h"
#include "strategies/MaxScoreDiscardStrategy.h"
#include "strategies/OptimisticDrawingStrategy.h"
#include "strategies/PessimisticDrawingStrategy.h"
#include "strategies/VariableRandomKnockingStrategy.h"
#include "strategies/PointThresholdKnockingStrategy.h"
#include "strategies/TurnThresholdKnockingStrategy.h"
#include "strategies/OppSuitTrackDiscardStrategy.h"
#include "strategies/MinOppGainDiscardStrategy.h"
#include "strategies/PointIncProbKnockingStrategy.h"
#include "strategies/PointBracketingKnockingStrategy.h"
#include "strategies/SimEVDiscardStrategy.h"
#include "strategies/PointIncProbDrawingStrategy.h"
#include "strategies/MaxMinDiscardStrategy.h"
#include "strategies/SimpleDrawingStrategy.h"
#include "strategies/SimEVKnockingStrategy.h"
#include "AgentGenome.h"
#include "AgentPopulation.h"
#include "ga/GASStateGA.h"
#include "ga/GASelector.h"
#include "strategies/ExpValueDrawingStrategy.h"
#include "Results.h"

#include <stdlib.h>
#include <iostream>
#include <sstream>

using namespace std;

/*
 *
 */
int main(int argc, char** argv) {

    srand(time(NULL));
    
    // Code for GA evaluation
    
    int popSize = 200;
    int nGen = 100;
    float pmut = 0.05;
    float pcross = 0.9;
    int limit = 3;
    
    for (int run = 0; run < limit; run++) {

        EvalType evalType = WR;
        AgentGenome genome(evalType);
        AgentPopulation population(genome, popSize);
        GATournamentSelector tournamentSelector;

        GASteadyStateGA ga(genome);
        ga.selector(tournamentSelector);
        ga.population(population);
        ga.populationSize(popSize);
        ga.pReplacement(0.2f);
        ga.nGenerations(nGen);
        ga.pMutation(pmut);
        ga.pCrossover(pcross);
        if (evalType != LSDA) {
            ga.minimaxi(ga.maximize());
        }
        else {
            ga.minimaxi(ga.minimize());
        }
        ga.evolve();
        
        const AgentGenome& winner = dynamic_cast<const AgentGenome&>(ga.statistics().bestIndividual());
        cout<< "Winner win ratio: " << winner.winRatio() << endl;
        cout<< "Winner persistence: " << winner.getNumGenerationsLived() << endl;
        cout<< winner.toString();
        cout<< "\n";
        cout<< ga.statistics().generation();
        ga.statistics().write("./stats");
        cout<< "\n";

        const AgentGenome* toFile[10];
        toFile[0] = &winner;
        for (int i = 1; i < 10; i++) {
            AgentGenome& runner_up = dynamic_cast<AgentGenome&>(ga.population().best(i+1));
            cout<< "Win ratio " << i << ": " << runner_up.winRatio() << endl;
            cout<< "Persistence " << i << ": " << runner_up.getNumGenerationsLived() << endl;
            toFile[i] = &runner_up;
        }
        ostringstream filename;
        filename << "best10_" << run;
        Results::writeToFile(filename.str(), toFile, 10);
    }
    
    // Code to match the top agents against each other
    
//    AgentGenome* heuristic1[3];
//    heuristic1[0] = Results::readFromFile("eval/sd_200_100_2/best10_0", 1)[0];
//    heuristic1[1] = Results::readFromFile("eval/sd_200_100_2/best10_1", 1)[0];
//    heuristic1[2] = Results::readFromFile("eval/sd_200_100_2/best10_2", 1)[0];
//    
//    AgentGenome* heuristic2[3];
//    heuristic2[0] = Results::readFromFile("eval/lsda_200_100/best10_0", 1)[0];
//    heuristic2[1] = Results::readFromFile("eval/lsda_200_100/best10_1", 1)[0];
//    heuristic2[2] = Results::readFromFile("eval/lsda_200_100/best10_2", 1)[0];
//    
//    int wins[2][3];
//    for (int i = 0; i < 2; i++) {
//        for (int j = 0; j < 3; j++) {
//            wins[i][j] = 0;
//        }
//    }
//    
//    for (int i = 0; i < 3; i++) {
//        Agent31* challenger = heuristic1[i]->buildAgent(0);
//        for (int j = 0; j < 3; j++) {
//            Agent31* opponent = heuristic2[j]->buildAgent(1);
//            Player* playerArray[2];
//            playerArray[0] = dynamic_cast<Player*>(challenger);
//            playerArray[1] = dynamic_cast<Player*>(opponent);
//            for (int k = 0; k < 20; k++) {
//                GameManager game(playerArray);
//                game.run();
//                MatchStatistics statistics = game.getMatchStatistics();
//                if (!statistics.loser == 0) {
//                    wins[0][i]++;
//                }
//                else {
//                    wins[1][j]++;
//                }
//            }
//            delete opponent;
//        }
//        delete challenger;
//    }
//    
//    for (int i = 0; i < 2; i++) {
//        cout<< "Win ratio group " << i << ":\n";
//        for (int j = 0; j < 3; j++) {
//            cout<< "Win ratio " << j << ": " << (float) wins[i][j]/60 << "\n";
//        }
//    }
    
    // Code to test agents with individual strategies
    
    
//    Player* players[NUM_PLAYERS];
//    for (int i=0; i<NUM_PLAYERS; i++) {
//        DiscardStrategy* agentDiscardStrategy = new MaxMinDiscardStrategy(100);
////        agentDiscardStrategy->setExecutionParameter(0, 10);
//        DrawingStrategy* agentDrawingStrategy = new SimpleDrawingStrategy(100);
//        agentDrawingStrategy->setDiscardStrategy(agentDiscardStrategy);
//        agentDrawingStrategy->setExecutionParameter(0, 50);
//        KnockingStrategy* agentKnockingStrategy = new SimEVKnockingStrategy(100);
//        agentKnockingStrategy->setExecutionParameter(0, 60);
//        agentKnockingStrategy->setExecutionParameter(1, 80);
//        
//        DiscardStrategy* agentEndDiscardStrategy = new MaxScoreDiscardStrategy(100);
//        DrawingStrategy* agentEndDrawingStrategy = new ExpValueDrawingStrategy(100);
//        agentEndDrawingStrategy->setDiscardStrategy(agentEndDiscardStrategy);
////        agentEndDrawingStrategy->setExecutionParameter(0, 10);
//        
//        players[i] = dynamic_cast<Player*>(new Agent31(i, agentKnockingStrategy,
//              agentDrawingStrategy,
//              agentDiscardStrategy,
//              agentEndDrawingStrategy,
//              agentEndDiscardStrategy));
//    }
//
//    GameManager game(players);
//    game.run();
//    for (int i = 0; i < NUM_PLAYERS; i++) {
//        cout<< "Player " << i << "\n";
//        CCardStack playerCards = players[i]->revealHand();
//        cout << playerCards.Initials() << "\n";
//        cout<< "Score: " << playerCards.Value() << "\n";
//    }

    cout<< "Done!\n";
    cout.flush();

    return (EXIT_SUCCESS);
}

